package com.netty.esc.config.shiro;

import com.netty.esc.Interceptor.filter.JwtFilter;
import com.netty.esc.config.shiro.realm.UserRealm;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

//    RequiresRoles-->RequiresPermissions-->RequiresAuthentication-->RequiresUser-->RequiresGuest
//    如果有个多个注解的话，前面的通过了会继续检查后面的，若不通过则直接返回
@Configuration
@Slf4j
public class ShiroConfig {
    /**
     * 注册shiro的Filter，拦截请求
     */

    @Bean("securityManager")
    public SecurityManager securityManager(UserRealm userRealm) {
        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        //设置manager
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(userRealm);
        return manager;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * @return org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor
     * @Description 开启shiro aop注解支持.使用代理方式;所以需要开启代码支持;
     * @Param [securityManager]
     **/
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
        filter.setSecurityManager(securityManager);

        //加入自定义的filter
        // setLoginUrl 如果不设置值，默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        //前后端分离项目中该链接应该为后端接口的访问url，通过该接口返回需要登录的状态码，由前端跳转至登录页面
        //shiroFilter.setLoginUrl("/user/login");
        // 设置无权限时跳转的 url;
        //shiroFilter.setUnauthorizedUrl("/user/test");
        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = filter.getFilters();


//        filterMap.put("anon",new DemoFilter());
        filterMap.put("jwt", new JwtFilter());
        filter.setFilters(filterMap);

        //定义相关路径
        filter.setLoginUrl("/login");
        filter.setUnauthorizedUrl("/noAuthorize");

        // 设置拦截器
        //定义拦截路径,记得将静态资源也排除过滤
        /*进行权限的控制,必须使用LinkHashMap,shrio要按照顺序进行设置*/
        Map<String, String> authMap = new LinkedHashMap<>();

        //anon:无参，开放权限，可以理解为匿名用户或游客
        authMap.put("/user/login", "anon");
        authMap.put("/user/sign", "anon");
        authMap.put("/user/code", "anon");
        authMap.put("/test/test4", "anon");
        authMap.put("/test/test3", "anon");
        //其余接口一律拦截
        //jwt:无参，需要认证
        authMap.put("/**", "jwt");

        filter.setFilterChainDefinitionMap(authMap);

        //配置完成
        log.info("shiro factory 创建成功");
        return filter;
    }

    @Bean("jwtFilter")
    public JwtFilter jwtFilter() {
        return new JwtFilter();
    }

    /**
     * SpringShiroFilter首先注册到spring容器
     * 然后被包装成FilterRegistrationBean
     * 最后通过FilterRegistrationBean注册到servlet容器
     * @return
     */
    @Bean
    @SuppressWarnings("all")
    public FilterRegistrationBean delegatingFilterProxy(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
}
